package com.shelpe.services.sinbadgateway.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;

import com.shelpe.services.sinbadgateway.security.AppTokenAuthenticationProvider;
import com.shelpe.services.sinbadgateway.security.AppTokenExtractFilter;
import com.shelpe.services.sinbadgateway.security.LoadBalanceRemoteTokenServices;
import com.shelpe.services.sinbadgateway.security.WebTokenExtractor;

import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class JsonWebTokenConfiguration extends WebSecurityConfigurerAdapter implements ResourceServerConfigurer{

	@Value("${security.contexts:sinbadgateway}")
	private String contexts;
	@Value("${spring.application.name}")
	private String applicationName;
	@Value("${oauth.php.token:sh2015sh}")
	private String phpTokenValue;
	@Value("${oauth.php.tokenName:token}")
	private String phpTokenName;
	@Value("${oauth.php.tokenLabel:php}")
	private String phpToken;
	
	@Autowired
	private LoadBalancerClient loadBalancerClient;
	@Autowired
	private ResourceServerProperties serverProperties;
	
	@Bean
	@Primary
	public ResourceServerTokenServices resourceServerTokenServices(){
		LoadBalanceRemoteTokenServices tokenServices = new LoadBalanceRemoteTokenServices();
		tokenServices.setClientId(this.serverProperties.getClientId());
		tokenServices.setClientSecret(this.serverProperties.getClientSecret());
		tokenServices.setLoadBalancerClient(loadBalancerClient);
		return tokenServices;
	}
	
	@Bean
	public WebTokenExtractor tokenExtractor(){
		WebTokenExtractor extractor = new WebTokenExtractor();
		extractor.setProxy(new BearerTokenExtractor());
		extractor.setTokenParameterName(this.phpTokenName);
		return extractor;
	}
	
	@Override
	public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
		resources.resourceId(this.applicationName);
		resources.tokenServices(this.resourceServerTokenServices());
		resources.tokenExtractor(this.tokenExtractor());
	}

	@Override
	public void configure(HttpSecurity http) throws Exception {
		if(this.contexts != null){
			String[] ctxs = this.contexts.split("\\,");
			for(String ctx:ctxs){
				log.debug("add {} to security matcher", ctx);
				http.requestMatchers().antMatchers("/" + ctx + "/**");
				//@see OAuth2SecurityExpressionMethods
				http.authorizeRequests().antMatchers("/" + ctx + "/**").access("#oauth2.hasAnyScope('openid', 'apptoken')");
			}
		}
		http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
		
		AppTokenExtractFilter filter = new AppTokenExtractFilter();
		filter.setTokenName(phpTokenName);
		filter.setAppName(this.phpToken);
		http.addFilterBefore(filter, AnonymousAuthenticationFilter.class);
		
		AppTokenAuthenticationProvider provider = new AppTokenAuthenticationProvider();
		provider.setAppToken(this.phpTokenValue);
		http.authenticationProvider(provider);
		
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		super.configure(web);
		web.ignoring().antMatchers(HttpMethod.OPTIONS);
	}

	
	
}
